#include "cellar.h"
#include "evaluate.h"
#include "testing.cpp"

/**
 * THIS FILE contains script-like functions for testing the attribute weight optimization
 */



inline bool compare(const std::pair<Result,std::vector<double> > & a ,const std::pair<Result,std::vector<double> >& b){
    return a.first.correct_ones() > b.first.correct_ones();
}

/**
 * @brief twoStageWeightOptimizer
 *
 * Experimental tests for two stage weight optimization
 * (was not included in the final report)
 */
inline int twoStageWeightOptimizer()
{
    std::string file = "set.csv";
    Cellar training(file);
    std::vector<Wine*> testing = training.getWinePointers();
    double fu = 0.25;
    training.setQforMinkowski(fu);
    training.setNumOfWinesForAveragePredict(7);
    training.setDistanceType(Cellar::SQUARED_EUCLIDEAN);

    std::string resultFileName = "result.txt";
    FileHandler fileHandler(resultFileName);
    std::vector<std::vector<double> > weightVecs;
    if(!fileHandler.readConfigForWeightVectors("config.txt", weightVecs))
    {
        std::cout << "Something wrong with the config file";
        return 1;
    }

    Result best;
    Result second;
    std::vector<std::pair<Result,std::vector<double> > >main_results;
    std::vector<std::vector<std::pair<Result,std::vector<double> > > >sisa_results;
    std::vector<std::vector <std::vector<std::pair<Result,std::vector<double> > > > > sisa_main_results;
    std::vector<std::pair<Result,std::vector<double> > >second_results;
    std::cout << "TOTAL WEIGHT VECTORS " << weightVecs.size() << std::endl;
    fileHandler.nextChapterInResultFile("Main weights");
    for(size_t i = 0; i < weightVecs.size(); i++){
        std::vector<double> copy(weightVecs[i]);
        best = findLocalMax(copy, training, testing, best);
        //fileHandler.updateResultFile("vector", copy, best);
        main_results.push_back(std::make_pair(best, copy));
        fileHandler.updateResultFile(std::to_string(i), copy, best, -1, best);
        std::cout << i << std::endl;
    }
    sort(main_results.begin(), main_results.end(), compare);
    fileHandler.nextChapterInResultFile("Best Main weights");
    for(auto i = 0; i < 3; i++)
        fileHandler.updateResultFile(std::to_string(i), main_results[i].second, main_results[i].first, -1, best);
    int count = 0;
    std::vector<double> empty_weights(11,0);
    Result empty_result;
    std::string info = "";
    for(auto j = main_results.begin(); j != main_results.begin() + 1; j++){
        training.setNumOfWinesForAveragePredict(7);
        best = j->first;
        fileHandler.nextChapterInResultFile(std::to_string(count));
        for(unsigned int i = 0; i < weightVecs.size(); i++)
        {
            std::vector<double> copy(weightVecs[i]);
            training.setNumOfWinesForAveragePredict(7);
            for(int k = 0; k < 7; k++){
                std::vector<double> copys_copy = copy;
                if(best.pre_wines[k].empty()){
                    info = std::to_string(i) + "  " + std::to_string(k) + "no entries";
                    fileHandler.updateResultFile(info, empty_weights, empty_result, -1, empty_result);
                }
                else{
                    second = findLocalMax(copys_copy, training, best.pre_wines[k], empty_result);
                    fileHandler.updateResultFile(std::to_string(i), copys_copy, second, k, best);

                    }
                }
            std::cout << count << "  " << i << std::endl;

        }
        count++;

    }
    fileHandler.nextChapterInResultFile("Best second weights");

    return weightVecs.size();
}

inline int weightOptimizer(std::string resultFileName, int k)
{
    std::string file = "set.csv";
    Cellar training(file);
    std::vector<Wine*> testing = training.getWinePointers();
    double fu = 0.25;
    training.setQforMinkowski(fu);
    training.setNumOfWinesForAveragePredict(k);
    training.setDistanceType(Cellar::SQUARED_EUCLIDEAN);

    FileHandler fileHandler(resultFileName);
    std::vector<std::vector<double> > weightVecs;
    if(!fileHandler.readConfigForWeightVectors("config.txt", weightVecs))
    {
        std::cout << "Something wrong with the config file";
        return 1;
    }

    Result best;
    std::vector<std::pair<Result,std::vector<double> > >main_results;
    std::cout << "TOTAL WEIGHT VECTORS " << weightVecs.size() << std::endl;
    fileHandler.nextChapterInResultFile("Main weights");
    for(size_t i = 0; i < weightVecs.size(); i++){
        std::vector<double> copy(weightVecs[i]);
        best = findLocalMax(copy, training, testing, best);
        //fileHandler.updateResultFile("vector", copy, best);
        main_results.push_back(std::make_pair(best, copy));
        fileHandler.updateResultFile(std::to_string(i), copy, best, -1, best);
        std::cout << i << "   " << best.correct_ones() << std::endl;
    }

    return weightVecs.size();
}


inline std::vector<std::string> & usplitSecond(std::string &s, char delim, std::vector<std::string> &elems) {
    std::stringstream ss(s);
    std::string item;
    while (std::getline(ss, item, delim)) {
        elems.push_back(item);
    }
    return elems;
}

inline std::vector<std::string> usplit(std::string &s, char delim) {
    std::vector<std::string> elems;
    usplitSecond(s, delim, elems);
    return elems;
}



inline int readResult(std::ifstream& stream, std::vector<double>& weights, double & score){
    std::string line;
    double value;
    getline(stream,line);
    std::vector<std::string> stringVec = usplit(line, ' ');
    getline(stream,line);
    stringVec = usplit(line, ' ');
    for(auto i = 0; i < 11; i++){
                value = atof(stringVec[i].c_str());
                weights[i] = value;
            }
    getline(stream, line);
    stringVec = usplit(line, ' ');
    score = atof(stringVec[1].c_str());
    return 0;
}

inline bool compareForFinal(const std::pair<std::vector<double>, double > & a ,const std::pair<std::vector<double>,double >& b){
        return a.second > b.second;
    }

inline int readFinalResults(int num_of_weight_vecs, std::string file_name, int k){
    std::vector<std::pair<std::vector<double>, double> >original_weights;
    std::ifstream stream(file_name);
    std::string line;
    getline(stream,line);
    double score;
    std::vector<double> weights(11,0);
    while(line != "-------- Main weights -------"){
        getline(stream,line);
    }

    for(auto i = 0; i < num_of_weight_vecs; i++){
        readResult(stream, weights, score);
        original_weights.push_back(std::make_pair(weights, score));
    }
    stream.close();

    std::sort(original_weights.begin(),original_weights.end(),compareForFinal);
    std::string file = "set.csv";
    Cellar training(file);
    training.setNumOfWinesForAveragePredict(k);
    training.setDistanceType(Cellar::SQUARED_EUCLIDEAN);
    file = "test.csv";
    Cellar temp_cellar(file, training.getLow(), training.getDif());
    std::vector<Wine*> testing = temp_cellar.getWinePointers();
    std::ofstream r_file("pre_to_f_score.txt");
    std::ofstream w_file("weights_for_ploted_scores.txt");
    Result r;

    for(int i = 0; i < 1; i += 1){
        training.setWeightsForWines(original_weights[i].first);
        for(auto j : original_weights[i].first)
            w_file << j << "   ";
        w_file << std::endl;
        r = evaluate(training, testing, r);
        r_file << original_weights[i].second/5000 << "   " << r.correct_ones()/1000 << "   " << calculateTotalFScore(r) << std::endl;
    }

    r_file.close();
    std::vector<double> ones(11,1);
    training.setWeightsForWines(original_weights[0].first);
    r = evaluate(training, testing, r);
    printTestResults(r);

    return 0;
}
